package com.superhero.website.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.poi.excel.ExcelWriter;
import com.superhero.common.Enum.RoleType;
import com.superhero.common.exception.BusinessException;
import com.superhero.common.pojo.PageInput;
import com.superhero.common.pojo.entity.AuthUser;
import com.superhero.common.pojo.entity.UserHealthInfo;
import com.superhero.common.pojo.vo.InspectorEnd.HealthInfoListVo;
import com.superhero.common.pojo.vo.PageVo;
import com.superhero.common.pojo.vo.website.HouseholdHealthInfo;
import com.superhero.common.pojo.vo.website.HouseholdListVo;
import com.superhero.common.repository.AccessRegistrationRepository;
import com.superhero.common.repository.AuthUserRepository;
import com.superhero.common.repository.UserHealthInfoRepository;
import com.superhero.common.utils.ExcelUtils;
import com.superhero.common.utils.OptionalUtil;
import com.superhero.website.service.HouseholdService;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.servlet.http.HttpServletResponse;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Service
public class HouseholdServiceImpl implements HouseholdService {

    @Autowired
    AuthUserRepository authUserRepository;
    @Autowired
    UserHealthInfoRepository userHealthInfoRepository;
    @Autowired
    AccessRegistrationRepository accessRegistrationRepository;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateConfirmedStatus(Integer id) {
        UserHealthInfo userHealthInfo = OptionalUtil.get(userHealthInfoRepository.findByUserId(id));
        Integer oldStatus = userHealthInfo.getConfirmed();
        userHealthInfo.setConfirmed(oldStatus == 0 ? 1 : 0);
        userHealthInfoRepository.saveAndFlush(userHealthInfo);
    }

    @Override
    public HouseholdHealthInfo getDetail(Integer id) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(id));
        if (authUser.getRole() != 1) {
            throw new BusinessException("该用户不是住户！");
        }
        UserHealthInfo userHealthInfo = authUser.getUserHealthInfo();
        if (userHealthInfo == null) {
            throw new BusinessException("该住户尚未填写健康登记表");
        }
        HouseholdHealthInfo householdHealthInfo = new HouseholdHealthInfo();
        BeanUtils.copyProperties(authUser, householdHealthInfo);
        BeanUtils.copyProperties(userHealthInfo, householdHealthInfo);
        householdHealthInfo.setId(authUser.getId());

        Integer symptoms = userHealthInfo.getSymptomsWithin14day();
        Integer observation = userHealthInfo.getIsolationObservation();
        Integer normal = userHealthInfo.getNormalTemperature();
        if (userHealthInfo.getConfirmed() == 1) {
            householdHealthInfo.setStatus(2);
        } else {
            if (normal == 1 && symptoms + observation == 0) {
                householdHealthInfo.setStatus(0);
            } else {
                householdHealthInfo.setStatus(1);
            }
        }
        householdHealthInfo.setNormalTemperature(userHealthInfo.getNormalTemperature());

        return householdHealthInfo;
    }

    @Override
    public PageVo showList(PageInput pageInput, String keyword, Integer personType) {
        Pageable pageable = PageRequest.of(pageInput.getPageNumber(), pageInput.getPageSize());

        // key可为人员用户名、姓名、手机号，地址，健康状态（正常/异常/确诊）的全模糊查询
        // 1. 筛选出相应的数据
        Page<AuthUser> households = authUserRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = exportListPredicate(root, criteriaBuilder, keyword, personType);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }), pageable);

        // 2.转换为封装的vo
        PageVo result = PageVo.convert(households);
        result.setContent(households.getContent().stream()
                .map(this::householdConvertToHouseholdListVo).collect(Collectors.toList()));
        return result;
    }

    @Override
    public ExcelWriter exportList(String keyword, Integer personType, HttpServletResponse response) {
        // key可为人员用户名、姓名、手机号，地址，健康状态（正常/异常/确诊）的全模糊查询
        // 1. 筛选出相应的数据
        List<AuthUser> households = authUserRepository.findAll(((root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = exportListPredicate(root, criteriaBuilder, keyword, personType);
            Predicate[] p = new Predicate[predicates.size()];
            criteriaQuery.orderBy(criteriaBuilder.desc(root.get("createTime")));
            return criteriaBuilder.and(predicates.toArray(p));
        }));

        // 2.转换为封装的vo
        List<HouseholdListVo> householdListVos = households.stream().map(this::householdConvertToHouseholdListVo).collect(Collectors.toList());
        if (!CollectionUtil.isEmpty(householdListVos)) {
            // 3. 设置模板头顺序
            ExcelWriter writer = getExportListExcelWriter();
            // 4. 进行写入
            return ExcelUtils.doExcelWriter(null, writer, householdListVos, HealthInfoListVo.class);
        }
        return null;
    }

    private ExcelWriter getExportListExcelWriter() {
        ExcelWriter writer = new ExcelWriter(true);
        writer.setOnlyAlias(true);
        writer.addHeaderAlias("username", "用户名");
        writer.addHeaderAlias("realName", "真实姓名");
        writer.addHeaderAlias("phone", "手机号");
        writer.addHeaderAlias("idCard", "身份证");
        writer.addHeaderAlias("personType", "人员类型（0-未认证 1=已认证 2-认证失败）");
        writer.addHeaderAlias("address", "地址");
        writer.addHeaderAlias("status", "健康状态（0-正常 1-异常 2-确诊）");
        return writer;
    }

    private List<Predicate> exportListPredicate(Root<AuthUser> root, CriteriaBuilder criteriaBuilder, String keyword, Integer personType) {
        List<Predicate> predicates = new ArrayList<>();

        predicates.add(criteriaBuilder.equal(root.get("locked"), "0"));
        if (personType == 0) {
            predicates.add(criteriaBuilder.equal(root.get("role"), RoleType.UNCERTIFICATION.ordinal()));
        } else if (personType == 1) {
            predicates.add(criteriaBuilder.equal(root.get("role"), RoleType.HOUSEHOLD.ordinal()));
        } else {
            predicates.add(criteriaBuilder.equal(root.get("role"), RoleType.FAIL.ordinal()));
        }
        if (!StringUtils.isEmpty(keyword)) {
            String key = "%" + keyword.trim() + "%";
            String upperKey = "%" + keyword.toUpperCase().trim() + "%";

            Predicate p1 = null, p2 = null, p3 = null, p4 = null, p5 = null, p6 = null, p7 = null;
            p1 = criteriaBuilder.like(criteriaBuilder.upper(root.get("username")), upperKey);
            p2 = criteriaBuilder.like(criteriaBuilder.upper(root.get("realName")), upperKey);
            p3 = criteriaBuilder.like(root.get("phone"), key);
            p4 = criteriaBuilder.like(criteriaBuilder.upper(root.join("userHealthInfo").get("address")), upperKey);
            predicates.add(criteriaBuilder.or(p1, p2, p3, p4));

            // 判断健康情况
            if ("健康".equals(key.trim())) {
                // 体温正常(1) and 其余无异常(0)
                p5 = criteriaBuilder.equal(root.join("userHealthInfo").get("normalTemperature").as(Integer.class), 1);
                p6 = criteriaBuilder.equal(root.join("userHealthInfo").get("isolationObservation").as(Integer.class), 0);
                p7 = criteriaBuilder.equal(root.join("userHealthInfo").get("symptomsWithin14day").as(Integer.class), 0);
                predicates.add(criteriaBuilder.and(p5, p6, p7));
            } else if ("异常".equals(key.trim())) {
                // 体温正常(1) and 其余中有一个有异常(1)
                p5 = criteriaBuilder.equal(root.join("userHealthInfo").get("normalTemperature").as(Integer.class), 1);
                p6 = criteriaBuilder.equal(root.join("userHealthInfo").get("isolationObservation").as(Integer.class), 1);
                p7 = criteriaBuilder.equal(root.join("userHealthInfo").get("symptomsWithin14day").as(Integer.class), 1);
                predicates.add(p5);
                predicates.add(criteriaBuilder.or(p6, p7));
            } else if ("确诊".equals(key.trim())) {
                predicates.add(criteriaBuilder.equal(root.join("userHealthInfo").get("confirmed").as(Integer.class), 1));
            }
        }
        return predicates;
    }

    private HouseholdListVo householdConvertToHouseholdListVo(AuthUser household) {
        HouseholdListVo householdListVo = new HouseholdListVo();

        BeanUtils.copyProperties(household, householdListVo);

        if (household.getUserHealthInfo() != null) {
            UserHealthInfo userHealthInfo = household.getUserHealthInfo();
            householdListVo.setPersonType(userHealthInfo.getPersonType());
            householdListVo.setAddress(userHealthInfo.getAddress());
            householdListVo.setLocked(userHealthInfo.getUser().getLocked());
            Integer role = userHealthInfo.getUser().getRole().equals(RoleType.HOUSEHOLD.ordinal()) ? 1 : 0;
            householdListVo.setCertification(role);

            // 判断健康状态
            Integer symptoms = userHealthInfo.getSymptomsWithin14day();
            Integer observation = userHealthInfo.getIsolationObservation();
            Integer normal = userHealthInfo.getNormalTemperature();
            Integer confirmed = userHealthInfo.getConfirmed();

            if (confirmed == 1) {
                householdListVo.setStatus(2);
            } else if (normal == 1 && symptoms + observation > 1) {
                householdListVo.setStatus(1);
            } else {
                householdListVo.setStatus(0);
            }
        }
        return householdListVo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Integer id) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(id));
        if (authUser.getRole() != 1) {
            throw new BusinessException("该用户不是住户，无法锁定账号！");
        }
        if (authUser.getLocked() == 0) {
            authUser.setLocked(1);
        } else {
            authUser.setLocked(0);
        }
        authUserRepository.save(authUser);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void verify(Integer id, Integer pass) {
        AuthUser authUser = OptionalUtil.get(authUserRepository.findById(id));
        RoleType roleType = RoleType.values()[authUser.getRole()];
        if (roleType == RoleType.HOUSEHOLD) {
            throw new BusinessException("该用户已认证过");
        }
        if (pass == 0) {
            authUser.setRole(RoleType.FAIL.ordinal());
        } else {
            authUser.setRole(RoleType.HOUSEHOLD.ordinal());
        }
        authUserRepository.saveAndFlush(authUser);
    }
}